package com.dream.dynamic_datasource.dynamic;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.dream.dynamic_datasource.entity.user.Db;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Map;
import java.util.Set;

/**
 * @description:
 * @author: Luo
 * @create: 2020-08-25 15:21
 */
@Data
public class DynamicDataSource extends AbstractRoutingDataSource {
    private final Logger log = LoggerFactory.getLogger(getClass());
    private Map<Object, Object> dynamicTargetDataSources;
    private Object dynamicDefaultTargetDataSource;
    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        this.dynamicDefaultTargetDataSource = defaultTargetDataSource;
    }


    @Override
    protected Object determineCurrentLookupKey() {
        String dbName = DynamicDataSourceContextHolder.getDataSourceRouterKey();
        if (!StringUtils.isEmpty(dbName)) {
            Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
            if (dynamicTargetDataSources2.containsKey(dbName)) {
                System.out.println("---当前数据源：" + dbName + "---");
            }
        } else {
            System.out.println("---当前数据源：默认数据源---");
        }
        return dbName;

    }
    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
        this.dynamicTargetDataSources = targetDataSources;

    }


    public void createDataSourceWithCheck(Db dataSource) throws Exception {
        Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
        //log.info("正在检查数据源："+dbName);
        String dbName = dataSource.getDbName();
        if (dynamicTargetDataSources2.containsKey(dbName)) {
            //log.info("数据源"+dbName+"之前已经创建，准备测试数据源是否正常...");
            DruidDataSource druidDataSource = (DruidDataSource) dynamicTargetDataSources2.get(dbName);
            boolean rightFlag = true;
            Connection connection = null;
            try {
                //log.info(dbName+"数据源的概况->当前闲置连接数："+druidDataSource.getPoolingCount());
                long activeCount = druidDataSource.getActiveCount();
                //log.info(dbName+"数据源的概况->当前活动连接数："+activeCount);
                //if(activeCount > 0) {
                //    log.info(dbName+"数据源的概况->活跃连接堆栈信息："+druidDataSource.getActiveConnectionStackTrace());
                //}
                //log.info("准备获取数据库连接...");
                connection = druidDataSource.getConnection();
                //log.info("数据源"+dbName+"正常");
            } catch (Exception e) {
                //log.error(e.getMessage(),e); //把异常信息打印到日志文件
                rightFlag = false;
                //log.info("缓存数据源"+dbName+"已失效，准备删除...");
                if(delDatasources(dbName)) {
                    log.info("缓存数据源删除成功");
                } else {
                    log.info("缓存数据源删除失败");
                }
            } finally {
                if(null != connection) {
                    connection.close();
                }
            }
            if(rightFlag) {
                log.info("不需要重新创建数据源");
            } else {
                log.info("准备重新创建数据源...");
                createDataSource(dataSource);
                log.info("重新创建数据源完成");
            }
        } else {
            createDataSource(dataSource);
        }

    }
    // 删除数据源
    private boolean delDatasources(String dbName) {
        Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
        if (dynamicTargetDataSources2.containsKey(dbName)) {
            Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
//#############################
            for (DruidDataSource l : druidDataSourceInstances) {
                if (dbName.equals(l.getName())) {
                    dynamicTargetDataSources2.remove(dbName);
                    DruidDataSourceStatManager.removeDataSource(l);
                    setTargetDataSources(dynamicTargetDataSources2);// 将map赋值给父类的TargetDataSources
                    super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }
    private  void createDataSource(Db dataSource)  {
        String dbName = dataSource.getDbName();
        //log.info("准备创建数据源"+dbName);
        String username = dataSource.getDbUser();
        String password = dataSource.getDbPwd();
        String url = dataSource.getDbUrl();
        String driveClass = "com.mysql.cj.jdbc.Driver";
        if(testDatasource(driveClass,url,username,password)) {
            this.createDataSource(dbName, driveClass, url, username, password);
            //if(!result) {
            //    //log.error("数据源"+datasourceId+"配置正确，但是创建失败");
            //}
        }
        //} else {
        //    //log.error("数据源配置有错误");
        //}
    }
    // 测试数据源连接是否有效
    private boolean testDatasource( String driveClass, String url, String username, String password) {
        try {
            Class.forName(driveClass);
            DriverManager.getConnection(url, username, password);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    // 创建数据源
    private boolean createDataSource(String dbName, String driveClass, String url, String username, String password) {
        try {
            try { // 排除连接不上的错误
                Class.forName(driveClass);
                DriverManager.getConnection(url, username, password);// 相当于连接数据库

            } catch (Exception e) {

                return false;
            }
            @SuppressWarnings("resource")
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setName(dbName);
            druidDataSource.setDriverClassName(driveClass);
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
            druidDataSource.init();
            this.dynamicTargetDataSources.put(dbName, druidDataSource);
            setTargetDataSources(this.dynamicTargetDataSources);// 将map赋值给父类的TargetDataSources
            super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
            //System.out.println(key+"数据源初始化成功");
            return true;
        } catch (Exception e) {
            //System.out.println(e + "");
            return false;
        }
    }
}

